home *** CD-ROM | disk | FTP | other *** search
/ Sun Solutions 1997 April to September / Sun Solutions CD - APR '97 - SEP '97 (704-3778-12 Rev. H)(Sun Microsystems, Inc.)(1997).iso / products / Hyperion / src / plat_bsd386.c < prev    next >
C/C++ Source or Header  |  1997-02-26  |  9KB  |  442 lines

  1. /*
  2.  * @(#)plat_bsd386.c    1.6    12/26/93
  3.  *
  4.  * BSD/386-specific drive control routines.
  5.  */
  6. static char *ident = "@(#)plat_bsd386.c    1.6 12/26/93";
  7.  
  8. #ifdef __bsdi__
  9.  
  10. #include <errno.h>
  11. #include <stdio.h>
  12. #include <sys/types.h>
  13. #include <fcntl.h>
  14. #include <sys/param.h>
  15. #include <sys/stat.h>
  16. #include <sys/time.h>
  17. #include <string.h>
  18. #include <sys/cdrom.h>
  19. #ifdef SOUNDBLASTER
  20. # include <i386/isa/sblast.h>
  21. #endif
  22.  
  23. #include "struct.h"
  24.  
  25. /*
  26.  * Since we can't sense the drive type with libcdrom anyway, and since the
  27.  * library doesn't provide "pause" or "resume" functions, use the daux field
  28.  * to point to the frame number at which we paused.
  29.  */
  30. struct pause_info {
  31.     int    frame;
  32.     int    endframe;
  33. };
  34. #define    PAUSE_FRAME    (((struct pause_info *) d->daux)->frame)
  35. #define    END_FRAME    (((struct pause_info *) d->daux)->endframe)
  36. #define CUR_CD        ((struct cdinfo *) d->aux)
  37.  
  38. void *malloc();
  39.  
  40. extern char    *cd_device;
  41.  
  42. #ifdef SOUNDBLASTER
  43.     int    min_volume = 0;
  44.     int    max_volume = 15;
  45.     int    min_volume_drive = 10;    /* Toshiba drive does low values. */
  46.     int    max_volume_drive = 255;
  47. #else /* not SOUNDBLASTER, libcdrom only */
  48.     int    min_volume = 10;
  49.     int    max_volume = 255;
  50. #endif
  51.  
  52. /*
  53.  * Initialize the drive.  A no-op for the generic driver.
  54.  */
  55. int
  56. gen_init(d)
  57.     struct wm_drive    *d;
  58. {
  59.     return (0);
  60. }
  61.  
  62. /*
  63.  * Get the number of tracks on the CD.
  64.  */
  65. int
  66. gen_get_trackcount(d, tracks)
  67.     struct wm_drive    *d;
  68.     int        *tracks;
  69. {
  70.     *tracks = CUR_CD->ntracks;
  71.  
  72.     return (0);
  73. }
  74.  
  75. /*
  76.  * Get the start time and mode (data or audio) of a track.
  77.  */
  78. int
  79. gen_get_trackinfo(d, track, data, startframe)
  80.     struct wm_drive    *d;
  81.     int        track, *data, *startframe;
  82. {
  83.     *data = (CUR_CD->tracks[track - 1].control & 4) ? 1 : 0;
  84.     *startframe = CUR_CD->tracks[track - 1].start_frame;
  85.  
  86.     return (0);
  87. }
  88.  
  89. /*
  90.  * Get the number of frames on the CD.
  91.  */
  92. int
  93. gen_get_cdlen(d, frames)
  94.     struct wm_drive    *d;
  95.     int        *frames;
  96. {
  97.     *frames = CUR_CD->total_frames;
  98.  
  99.     return (0);
  100. }
  101.  
  102. /*
  103.  * Get the current status of the drive: the current play mode, the absolute
  104.  * position from start of disc (in frames), and the current track and index
  105.  * numbers if the CD is playing or paused.
  106.  */
  107. int
  108. gen_get_drive_status(d, oldmode, mode, pos, track, index)
  109.     struct wm_drive    *d;
  110.     enum cd_modes    oldmode, *mode;
  111.     int        *pos, *track, *index;
  112. {
  113.     struct cdstatus    status;
  114.     extern enum cd_modes cur_cdmode;
  115.  
  116.     /* If we can't get status, the CD is ejected, so default to that. */
  117.     *mode = EJECTED;
  118.  
  119.     /* Is the device open? */
  120.     if (d->aux == NULL)
  121.     {
  122.         switch (wmcd_open(d)) {
  123.         case -1:    /* error */
  124.             return (-1);
  125.  
  126.         case 1:        /* retry */
  127.             return (0);
  128.         }
  129.     }
  130.  
  131.     if (cdstatus (CUR_CD, &status) < 0)
  132.     {
  133.         *mode = TRACK_DONE;    /* waiting for next track. */
  134.         return (0);
  135.     }
  136.  
  137. #define DOPOS \
  138.         *pos = status.abs_frame; \
  139.         *track = status.track_num; \
  140.         *index = status.index_num
  141.  
  142.     switch (status.state) {
  143.     case cdstate_playing:
  144.         *mode = PLAYING;
  145.         DOPOS;
  146.         break;
  147.  
  148.     case cdstate_stopped:
  149.         /* the MITSUMI drive doesn't have a "paused" state,
  150.            so it always comes here and not to the paused section.
  151.            The PAUSE_FRAME stuff below (in gen_pause())
  152.            fakes out the paused state. */
  153.         if (oldmode == PLAYING) {
  154.             *mode = TRACK_DONE;
  155.             break;
  156.         } else if (cur_cdmode != PAUSED) {
  157.             *mode = STOPPED;
  158.             DOPOS;
  159.             break;
  160.         }
  161.         /* fall through if paused */
  162.  
  163.     case cdstate_paused:
  164.         /* the SCSI2 code in the cdrom library only pauses with
  165.            cdstop(); it never truly stops a disc (until an in-progress
  166.            play reaches the end).  So it always comes here. */
  167.         if (cur_cdmode == STOPPED) {
  168.             *mode = STOPPED;
  169.             DOPOS;
  170.             break;
  171.         }
  172.         if (oldmode == PLAYING || oldmode == PAUSED) {
  173.             *mode = PAUSED;
  174.             DOPOS;
  175.         } else {
  176.             *mode = STOPPED;
  177.             DOPOS;
  178.         }
  179.         break;
  180.  
  181.     default:
  182.         *mode = STOPPED;
  183.     }
  184.  
  185.     return (0);
  186. }
  187.  
  188. /*
  189.  * Return a volume value suitable for passing to the CD-ROM drive.  "vol"
  190.  * is a volume slider setting; "max" is the slider's maximum value.
  191.  */
  192. static int
  193. scale_volume(vol, max)
  194.     int    vol, max;
  195. {
  196.     /* on Toshiba XM-3401B drive, and on soundblaster, this works fine. */
  197.     return ((vol * (max_volume - min_volume)) / max + min_volume);
  198. }
  199.  
  200. /*
  201.  * Set the volume level for the left and right channels.  Their values
  202.  * range from 0 to 100.
  203.  */
  204. int
  205. gen_set_volume(d, left, right)
  206.     struct wm_drive    *d;
  207.     int        left, right;
  208. {
  209.     left = scale_volume(left, 100);
  210.     right = scale_volume(right, 100);
  211.  
  212. #ifdef SOUNDBLASTER
  213.     /* Send a Mixer IOCTL */
  214.     if (d->fd >= 0) {
  215.         struct sb_mixer_levels levels;
  216.         if (ioctl(d->fd, MIXER_IOCTL_READ_LEVELS, &levels) == 0) {
  217.             levels.cd.l = left < 0 ? 0 : left;
  218.             levels.cd.r = right < 0 ? 0 : right;
  219.             (void) ioctl(d->fd, MIXER_IOCTL_SET_LEVELS, &levels);
  220.         } else
  221.             perror("SoundBlaster mixer read failed");
  222.     } else
  223. #endif
  224.     /* NOTE: the cdvolume2() call is an addition to the cdrom library.
  225.        Pick it up from the archives on bsdi.com */
  226.     cdvolume2 (CUR_CD, left < 0 ? 0 : left > 255 ? 255 : left,
  227.            right < 0 ? 0 : right > 255 ? 255 : right);
  228.  
  229.     return (0);
  230. }
  231.  
  232. /*
  233.  * Pause the CD.  This is a bit of a trick since there's no cdpause()
  234.  * function in the library.  We fake it by saving the frame number
  235.  * and stopping.
  236.  */
  237. int
  238. gen_pause(d)
  239.     struct wm_drive    *d;
  240. {
  241.     struct cdstatus    status;
  242.  
  243.     if (cdstatus(d->aux, &status) < 0)
  244.         return (-1);
  245.     if (status.state != cdstate_playing)
  246.         PAUSE_FRAME = CUR_CD->tracks[0].start_frame;
  247.     else
  248.         PAUSE_FRAME = status.abs_frame;
  249.     if (cdstop(d->aux) < 0)
  250.         return (-1);
  251.  
  252.     return (0);
  253. }
  254.  
  255. /*
  256.  * Resume playing the CD (assuming it was paused.)
  257.  */
  258. int
  259. gen_resume(d)
  260.     struct wm_drive    *d;
  261. {
  262.     int    status;
  263.  
  264.     status = (d->play)(d, PAUSE_FRAME, END_FRAME);
  265.     PAUSE_FRAME = 0;
  266.     return (status);
  267. }
  268.  
  269. /*
  270.  * Stop the CD.
  271.  */
  272. int
  273. gen_stop(d)
  274.     struct wm_drive *d;
  275. {
  276.     return cdstop(d->aux);
  277. }
  278.  
  279. /*
  280.  * Play the CD from one position to another (both in frames.)
  281.  */
  282. int
  283. gen_play(d, start, end)
  284.     struct wm_drive    *d;
  285.     int        start, end;
  286. {
  287.     END_FRAME = end;
  288.     if (cdplay(d->aux, start, end) < 0)
  289.         return (-1);
  290.     else
  291.         return (0);
  292. }
  293.  
  294. /*
  295.  * Eject the current CD, if there is one.
  296.  */
  297. int
  298. gen_eject(d)
  299.     struct wm_drive    *d;
  300. {
  301.     cdeject(d->aux);
  302.     cdclose(d->aux);
  303.     d->aux = NULL;
  304.     free(d->daux);
  305.     d->daux = NULL;
  306.  
  307.     return (0);
  308. }
  309.  
  310. /*
  311.  * unscale_volume(cd_vol, max)
  312.  *
  313.  * Given a value between min_volume and max_volume, return the volume slider
  314.  * value needed to achieve that value.
  315.  *
  316.  * Rather than perform floating-point calculations to reverse the above
  317.  * formula, we simply do a binary search of scale_volume()'s return values.
  318.  */
  319. static int
  320. unscale_volume(cd_vol, max)
  321.     int    cd_vol, max;
  322. {
  323.     int    vol = 0, top = max, bot = 0, scaled;
  324.  
  325.     while (bot <= top)
  326.     {
  327.         vol = (top + bot) / 2;
  328.         scaled = scale_volume(vol, max);
  329.         if (cd_vol == scaled)
  330.             break;
  331.         if (cd_vol < scaled)
  332.             top = vol - 1;
  333.         else
  334.             bot = vol + 1;
  335.     }
  336.     
  337.     if (vol < 0)
  338.         vol = 0;
  339.     else if (vol > max)
  340.         vol = max;
  341.  
  342.     return (vol);
  343. }
  344.  
  345. /*
  346.  * Read the initial volume from the drive, if available.  Each channel
  347.  * ranges from 0 to 100, with -1 indicating data not available.
  348.  */
  349. int
  350. gen_get_volume(d, left, right)
  351.     struct wm_drive    *d;
  352.     int        *left, *right;
  353. {
  354.     /* Most systems can't seem to do this... */
  355.     *left = *right = -1;
  356.  
  357. #ifdef SOUNDBLASTER
  358.     /* Send a Mixer IOCTL */
  359.     if (d->fd >= 0) {
  360.         struct sb_mixer_levels levels;
  361.         if (ioctl(d->fd, MIXER_IOCTL_READ_LEVELS, &levels) == 0) {
  362.         *left = unscale_volume(levels.cd.l, 100);
  363.         *right = unscale_volume(levels.cd.r, 100);
  364.         } else
  365.         perror("SoundBlaster mixer read failed");
  366.     }
  367. #endif
  368.  
  369.     return (0);
  370. }
  371.  
  372. /*
  373.  * Send an arbitrary SCSI command to a device.
  374.  */
  375. int
  376. wm_scsi(d, cdb, cdblen, retbuf, retbuflen, getreply)
  377.     struct wm_drive    *d;
  378.     unsigned char    *cdb;
  379.     int        cdblen;
  380.     void        *retbuf;
  381.     int        retbuflen;
  382.     int        getreply;
  383. {
  384.     /* Don't know how to do SCSI passthrough... */
  385.     return (-1);
  386. }
  387.  
  388. #ifdef SOUNDBLASTER
  389. int    sb_fd = -3;            /* patchable from external programs */
  390. #endif
  391.  
  392. /*
  393.  * Open the CD device.  We can't determine the drive type under BSD/386.
  394.  */
  395. int
  396. wmcd_open(d)
  397.     struct wm_drive    *d;
  398. {
  399.     void    *aux = NULL, *daux = NULL;
  400.     int fd = -1;
  401.  
  402.     if (d->aux)    /* Device already open? */
  403.         return (0);
  404.  
  405.     if ((aux = cdopen(cd_device)) == NULL)
  406.     {
  407.         fprintf(stderr, "No cdrom found by libcdrom\n");
  408.         exit(1);
  409.     }
  410.  
  411.     if ((daux = malloc(sizeof(struct pause_info))) == NULL)
  412.         return (-1);
  413.  
  414. #ifdef SOUNDBLASTER
  415.     if (sb_fd != -3 && sb_fd < 0)
  416.         fd = open ("/dev/sb_mixer", O_RDWR, 0);
  417.     if (fd < 0) {
  418.         if (sb_fd != -3)
  419.         fprintf (stderr,"SoundBlaster mixer not found/disabled; will use direct CD volume control\n");
  420.         max_volume = max_volume_drive;
  421.         min_volume = min_volume_drive;
  422.     }
  423. #endif
  424.  
  425.     /* Now fill in the relevant parts of the wm_drive structure. */
  426.     *d = *(find_drive_struct("", "", ""));
  427.     d->aux = aux;
  428.     d->daux = daux;
  429.     d->fd = fd;
  430.     PAUSE_FRAME = 0;
  431.     END_FRAME = 0;
  432.  
  433.     (d->init)(d);
  434.  
  435.     return (0);
  436. }
  437.  
  438. void
  439. keep_cd_open() { }
  440.  
  441. #endif /* __bsdi__ */
  442.